package com.icss.train_sys_back.service.statistics_manage.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.icss.train_sys_back.entity.statistics_manage.PopularStationEntity;
import com.icss.train_sys_back.entity.statistics_manage.PopularTrainsEntity;
import com.icss.train_sys_back.entity.statistics_manage.SalesTrendEntity;
import com.icss.train_sys_back.entity.statistics_manage.TicketStatisticsEntity;
import com.icss.train_sys_back.mapper.statistics_manage.TicketStatisticsManageMapper;
import com.icss.train_sys_back.service.statistics_manage.TicketStatisticsManageService;
import com.icss.train_sys_back.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Author 小泽
 * @createTime 2025/10/9 9:23
 */
@Service
@Slf4j
public class TicketStatisticsManageServiceImpl implements TicketStatisticsManageService {
    @Autowired
    private TicketStatisticsManageMapper ticketStatisticsManageMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    //票务统计分析
    //ps   dateType = week ,  startDate = null , endDate = null , trainType = D , station = 2
    @Override
    public TicketStatisticsEntity ticketStatistics(
            String dateType, String trainType,
            Integer station, String startDateStr,
            String endDateStr
    ) {
        //dateType --- (时间类型，可选值：'day', 'week', 'month', 'year', 'custom')
        // 转换日期参数
        LocalDate startDate = DateUtil.stringToLocalDate(startDateStr);
        LocalDate endDate = DateUtil.stringToLocalDate(endDateStr);
        switch (dateType) {
            case "day":
                startDate = LocalDate.now();
                endDate = LocalDate.now().plusDays(1);
                break;
            case "week":
                LocalDate now = LocalDate.now();
                int dayOfWeek = now.getDayOfWeek().getValue();
                startDate = now.minusDays(dayOfWeek - 1); // 周一
                endDate = now.plusDays(1); // 明天（包含今天）
                break;
            case "month":
                int currentMonthValue = LocalDate.now().getMonthValue();
                startDate = LocalDate.of(LocalDate.now().getYear(), currentMonthValue, 1); // 本月1号
                endDate = LocalDate.now().plusDays(1); // 明天（包含今天）
                break;
            case "year":
                int year = LocalDate.now().getYear();
                startDate = LocalDate.of(year, 1, 1); // 本年1月1号
                endDate = LocalDate.now().plusDays(1); // 明天（包含今天）
                break;
            case "custom":
                startDate = LocalDate.parse(startDateStr);
                endDate = LocalDate.parse(endDateStr);
                break;
        }

        TicketStatisticsEntity ticketStatistics;

        // 设计Redis键：包含查询参数以确保唯一性
        String redisKey = String.format("ticket:statistics:%s:%s:%s:%s:%s",
                dateType,
                Objects.toString(trainType, "all"),
                Objects.toString(station, "all"),
                startDate.toString(),
                endDate.toString());

        try {
            // 先查询redis中是否存在数据
            String cachedData = stringRedisTemplate.opsForValue().get(redisKey);
            if (!cachedData.isEmpty()) {
                // 如果缓存存在，直接返回缓存数据（这里需要实现JSON反序列化）
                // 使用Jackson等JSON工具进行反序列化
                ObjectMapper objectMapper = new ObjectMapper();
                ticketStatistics = objectMapper.readValue(cachedData, TicketStatisticsEntity.class);
                log.info("从Redis缓存获取票务统计数据");
                return ticketStatistics;
            }
        } catch (Exception e) {
            log.error("Redis查询错误: {}", e.getMessage());
            // Redis出错不影响业务，继续从数据库查询
        }

        // 调用Mapper查询统计数据
        ticketStatistics = ticketStatisticsManageMapper.getTicketStatistics(startDate.toString(), endDate.toString(), trainType, station);

        // 将查询结果存入Redis
        try {
            if (ticketStatistics != null) {
                ObjectMapper objectMapper = new ObjectMapper();
                String jsonData = objectMapper.writeValueAsString(ticketStatistics);

                // 根据不同的时间类型设置不同的过期时间
                long expireTime = getExpireTimeByDateType(dateType);
                stringRedisTemplate.opsForValue().set(redisKey, jsonData, expireTime, TimeUnit.MINUTES);
                log.info("票务统计数据已缓存到Redis，过期时间: {}分钟", expireTime);
            }
        } catch (Exception e) {
            log.error("Redis缓存写入错误: {}", e.getMessage());
            // Redis缓存失败不影响返回数据
        }

        return ticketStatistics;
    }

    //根据时间类型设置不同的缓存过期时间
    private long getExpireTimeByDateType(String dateType) {
        return switch (dateType) {
            case "day" -> 30; // 30分钟
            case "month" -> 60; // 1小时
            case "year" -> 120; // 2小时
            default -> 60; // 默认1小时
        };
    }

    //当月销售额统计
    @Override
    public SalesTrendEntity salesTrend() {
        // 获取当前月份作为缓存键的一部分
        int monthValue = LocalDate.now().getMonthValue();
        int yearValue = LocalDate.now().getYear();
        String redisKey = String.format("ticket:salesTrend:%d:%d", yearValue, monthValue);

        try {
            // 先查询redis中是否存在数据
            String cachedData = stringRedisTemplate.opsForValue().get(redisKey);
            if (!cachedData.isEmpty()) {
                ObjectMapper objectMapper = new ObjectMapper();
                SalesTrendEntity salesTrend = objectMapper.readValue(cachedData, SalesTrendEntity.class);
                log.info("从Redis缓存获取销售趋势数据");
                return salesTrend;
            }
        } catch (Exception e) {
            log.error("Redis查询错误: {}", e.getMessage());
        }

        //获取当月天数
        int lengthOfMonth = LocalDate.now().lengthOfMonth();

        //查询当月的所有数据
        List<Map<String, Object>> dailyData = ticketStatisticsManageMapper.salesTrendList(monthValue);

        //创建并初始化结果实体
        SalesTrendEntity salesTrend = new SalesTrendEntity();
        String[] dates = new String[lengthOfMonth];
        double[] salesData = new double[lengthOfMonth];
        Integer[] ticketCountData = new Integer[lengthOfMonth];

        //初始化销售额和售票量为0
        for (int i = 0; i < lengthOfMonth; i++) {
            dates[i] = String.valueOf(i + 1); //存储具体日期（1,2,3...）
            salesData[i] = 0.0;
            ticketCountData[i] = 0;
        }
        //填充查询到的数据
        for (Map<String, Object> data : dailyData) {
            String dateStr = data.get("date").toString();
            //解析日期获取具体是当月的第几天
            try {
                // 方法1：只提取年月日部分（前10个字符）
                if (dateStr.length() >= 10) {
                    String pureDateStr = dateStr.substring(0, 10); // 提取 yyyy-MM-dd 部分
                    LocalDate date = LocalDate.parse(pureDateStr);
                    int dayOfMonth = date.getDayOfMonth();

                    //确保日期在当月范围内
                    if (dayOfMonth <= lengthOfMonth && date.getMonthValue() == monthValue) {
                        //填充对应的销售额和售票量数据
                        if (data.get("sales") != null) {
                            salesData[dayOfMonth - 1] = Double.parseDouble(data.get("sales").toString());
                        }
                        if (data.get("ticketCount") != null) {
                            ticketCountData[dayOfMonth - 1] = Integer.parseInt(data.get("ticketCount").toString());
                        }
                    }
                }
            } catch (Exception e) {
                log.error("日期处理错误: {}", e.getMessage());
            }
        }
        //设置实体的属性
        salesTrend.setDates(dates);
        salesTrend.setSalesData(salesData);
        salesTrend.setTicketCountData(ticketCountData);

        // 将查询结果存入Redis
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            String jsonData = objectMapper.writeValueAsString(salesTrend);
            stringRedisTemplate.opsForValue().set(redisKey, jsonData, 30, TimeUnit.MINUTES); // 30分钟过期
            log.info("销售趋势数据已缓存到Redis");
        } catch (Exception e) {
            log.error("Redis缓存写入错误: {}", e.getMessage());
        }

        return salesTrend;
    }

    //热门车次统计
    @Override
    public List<PopularTrainsEntity> popularTrains(String startDate, String endDate) {
        // 设计Redis键：包含时间范围参数
        String redisKey;
        if (startDate != null && endDate != null) {
            redisKey = String.format("ticket:popularTrains:%s:%s", startDate, endDate);
        } else {
            //未指定时间，选择当年的热门车次
            int year = LocalDate.now().getYear();
            redisKey = String.format("ticket:popularTrains:year:%d", year);
            startDate = LocalDate.of(year, 1, 1).toString();
            endDate = LocalDate.of(year, 12, 31).toString();
        }

        try {
            // 先查询redis中是否存在数据
            String cachedData = stringRedisTemplate.opsForValue().get(redisKey);
            if (!cachedData.isEmpty()) {
                ObjectMapper objectMapper = new ObjectMapper();
                // 反序列化List
                List<PopularTrainsEntity> result = objectMapper.readValue(cachedData,
                    objectMapper.getTypeFactory().constructCollectionType(List.class, PopularTrainsEntity.class));
                log.info("从Redis缓存获取热门车次数据");
                return result;
            }
        } catch (Exception e) {
            log.error("Redis查询错误: {}", e.getMessage());
        }

        List<PopularTrainsEntity> result = ticketStatisticsManageMapper.popularTrains(startDate, endDate);

        // 将查询结果存入Redis
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            String jsonData = objectMapper.writeValueAsString(result);
            stringRedisTemplate.opsForValue().set(redisKey, jsonData, 60, TimeUnit.MINUTES); // 1小时过期
            log.info("热门车次数据已缓存到Redis");
        } catch (Exception e) {
            log.error("Redis缓存写入错误: {}", e.getMessage());
        }

        return result;
    }

    //热门站点
    @Override
    public List<PopularStationEntity> popularStations(String startDate, String endDate) {
        // 设计Redis键：包含时间范围参数
        String redisKey;
        if (startDate != null && endDate != null) {
            redisKey = String.format("ticket:popularStations:%s:%s", startDate, endDate);
        } else {
            //未指定时间，选择当年的热门站点
            int year = LocalDate.now().getYear();
            redisKey = String.format("ticket:popularStations:year:%d", year);
            startDate = LocalDate.of(year, 1, 1).toString();
            endDate = LocalDate.of(year, 12, 31).toString();
        }

        try {
            // 先查询redis中是否存在数据
            String cachedData = stringRedisTemplate.opsForValue().get(redisKey);
            if (!cachedData.isEmpty()) {
                ObjectMapper objectMapper = new ObjectMapper();
                // 反序列化List
                List<PopularStationEntity> result = objectMapper.readValue(cachedData,
                    objectMapper.getTypeFactory().constructCollectionType(List.class, PopularStationEntity.class));
                log.info("从Redis缓存获取热门站点数据");
                return result;
            }
        } catch (Exception e) {
            log.error("Redis查询错误: {}", e.getMessage());
        }

        List<PopularStationEntity> result = ticketStatisticsManageMapper.popularStations(startDate, endDate);

        // 将查询结果存入Redis
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            String jsonData = objectMapper.writeValueAsString(result);
            stringRedisTemplate.opsForValue().set(redisKey, jsonData, 60, TimeUnit.MINUTES); // 1小时过期
            log.info("热门站点数据已缓存到Redis");
        } catch (Exception e) {
            log.error("Redis缓存写入错误: {}", e.getMessage());
        }

        return result;
    }


}
